﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Snowdreamist.Text.UBB
{
    /// <summary>
    /// The fastest factory
    /// The factory by default
    /// </summary>
    public class PrefixAggregateUBBElementFactory : IUBBElementFactory
    {
        public readonly static IPrefixUBBElementFactory[] DefaultFactories = new IPrefixUBBElementFactory[]
        {
            new SimpleUBBElementFactory("b", new Func<UBBElement>(()=> new BoldElement())),
            new SimpleUBBElementFactory("i", new Func<UBBElement>(()=> new ItalicElement())),
            new SimpleUBBElementFactory("u", new Func<UBBElement>(()=> new UnderlineElement())),
            new SimpleUBBElementFactory("del", new Func<UBBElement>(()=> new StrikethroughElement())),
            new SimpleUBBElementFactory("code", new Func<UBBElement>(()=> new CodeElement())),
            new SimpleUBBElementFactory("right",new Func<UBBElement>(()=> new AlignElement(AlignType.Right))),
            new SimpleUBBElementFactory("left",new Func<UBBElement>(()=> new AlignElement(AlignType.Left))),
            new SimpleUBBElementFactory("center",new Func<UBBElement>(()=> new AlignElement(AlignType.Center))),
            new AlignFactory(),
            new ColorFactory(),
            new FloatFactory(),
            new FontFactory(),
            new ImageFactory(),
            new ListFactory(),
            new SizeFactory()
            // NOTE: no textfactory
        };

        public PrefixAggregateUBBElementFactory() : this(DefaultFactories) { }

        public PrefixAggregateUBBElementFactory(IEnumerable<IPrefixUBBElementFactory> factories)
        {
            if (factories == null)
                throw new ArgumentNullException("factories");
            // order by length from large to small
            this._factories = factories.OrderByDescending(p => p.Prefix.Length).ToArray();
        }

        public bool IsLabel(string content, out IUBBElementFactory factory)
        {
            // scan prefix
            foreach (var f in this._factories)
                if (content.StartsWith(f.Prefix, StringComparison.OrdinalIgnoreCase))
                {
                    // hit
                    if (string.Compare(content, f.Prefix, true) == 0)
                    {
                        factory = f;
                        return true;
                    }
                    else
                        return f.IsLabel(content, out factory);
                }
            // not found
            factory = null;
            return false;
        }

        public UBBElement Create(UBBContent ubbContent)
        {
            throw new NotSupportedException();
        }

        /// <summary>
        /// All factories
        /// </summary>
        public IEnumerable<IPrefixUBBElementFactory> Factories
        {
            get
            {
                return this._factories;
            }
        }

        #region private

        private IPrefixUBBElementFactory[] _factories;

        #endregion private
    }

    public interface IPrefixUBBElementFactory : IUBBElementFactory
    {
        string Prefix { get; }
    }

    public abstract class PrefixUBBElementFactory : IPrefixUBBElementFactory
    {
        public PrefixUBBElementFactory(string prefix)
        {
            if (string.IsNullOrWhiteSpace(prefix))
                throw new ArgumentException("Invalid prefix");
            this.Prefix = prefix;
        }

        public string Prefix { get; private set; }

        public virtual bool IsLabel(string content, out IUBBElementFactory factory)
        {
            factory = this;
            return true;
        }

        public abstract UBBElement Create(UBBContent ubbContent);
    }
}